import cv2
import numpy as np
import math
# 开始图像处理，读取图片文件
image = cv2.imread("pic/5.png")
image_copy = image.copy()
#image_mix = cv2.imread(Config.drc)
cv2.imshow("image", image)
#cv2.imshow("image_mix", image_mix)
#获取原始\目标图像的大小
srcHeight,srcWidth ,channels = image.shape
#drcHeight,drcWidth ,channels_drc = image_mix.shape

# 镶嵌的图的四个顶点
#box_drc=np.array([[0, 0],[drcWidth, 0],[drcWidth, drcHeight],[0, drcHeight]])
#dst_rect = np.float32([box_drc[0], box_drc[1], box_drc[2], box_drc[3]])
#转成灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 中值滤波平滑，消除噪声
# 当图片缩小后，中值滤波的孔径也要相应的缩小，否则会将有效的轮廓擦除
binary = cv2.medianBlur(gray,5)
#转换为二值图像
ret, binary = cv2.threshold(binary, 160, 255, cv2.THRESH_BINARY)
cv2.imshow("binary", binary)
#cv2.waitKey(0)


# 找出外接四边形, c是轮廓的坐标数组
def boundingBox(idx, c):
    if len(c) < 2:
        return None
    epsilon = 30
    while True:
        approxBox = cv2.approxPolyDP(c, epsilon, True)
        # 求出拟合得到的多边形的面积,连通区域，用格林公式
        theArea = math.fabs(cv2.contourArea(approxBox))
        # 输出拟合信息
        print("contour idx: %d ,contour_len: %d ,epsilon: %d ,approx_len: %d ,approx_area: %s" % (
        idx, len(c), epsilon, len(approxBox), theArea))
        if (len(approxBox) < 4):
            return None
        if theArea > 0:
            if (len(approxBox) > 4):
                # epsilon 增长一个步长值
                epsilon += 1
                continue
            else:  # approx的长度为4，表明已经拟合成矩形了
                # 转换成4*2的数组
                approxBox = approxBox.reshape((4, 2))
                return approxBox
        else:
            print("failed to find boundingBox,idx = %d area=%f" % (idx, theArea))
            return None

#对坐标点进行排序
def order_points(pts):
    # 初始化将要排序的坐标列表
    # 所以列表中的第一个条目是左上角，
    # 第二条是右上角，第三条是右下角，第四条是左下角
    rect = np.zeros((4, 2), dtype="int")

    # 左上角的和最小，而右下角的和最大
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # 计算两个点之间的差异，右上角的差异最小，而左下角的差异最大，点的x,y做差，y-x，右上角为负数，左下角为正数，其余接近0
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    # [top-left, top-right, bottom-right, bottom-left]
    return rect

# canny 边缘检测
binary = cv2.Canny(binary, 190, 255, 1)
#显示边缘检测的结果
cv2.imshow("Canny", binary)
# 提取轮廓
contours,_ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
## 输出轮廓数目
print("the count of contours is  %d \n"%(len(contours)))

# 针对每个轮廓，拟合外接四边形,如果成功，则将记录该四个点

s=0
BOX=np.zeros((4, 2), dtype="int")
for idx, c in enumerate(contours):
    approxBox = boundingBox(idx, c)
    if approxBox is None:
        #        print("\n")
        continue

    # 获取最小矩形包络
    rect = cv2.minAreaRect(approxBox)# 得到最小外接矩形的（中心(x,y), (宽,高), 旋转角度），approxBox是array对象，任意点集
    box = cv2.boxPoints(rect)# 获取最小外接矩形的4个顶点坐标
    box = box.reshape(4, 2)
    box = order_points(box)
    if cv2.contourArea(box)>s:
        s=cv2.contourArea(box)
        BOX=box
color=(36, 255, 12)
thickness=2
cv2.line(image, tuple(BOX[0]), tuple(BOX[1]), color, thickness)
cv2.line(image, tuple(BOX[1]), tuple(BOX[2]), color, thickness)
cv2.line(image, tuple(BOX[2]), tuple(BOX[3]), color, thickness)
cv2.line(image, tuple(BOX[3]), tuple(BOX[0]), color, thickness)


    #print("boundingBox：\n", box)

#cv2.imwrite('pic/detected5.png', image)
cv2.imshow("detected", image)
cv2.waitKey(0)
